﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
using System.ServiceModel;
using System.Text;
using System.Security.Cryptography;
using System.Net.Mail;
using System.Net;
using System.IO;
using System.Drawing;
using System.Drawing.Imaging;
using System.Net.Mime;
using iTextSharp.text;
using iTextSharp.text.pdf;
using Google.GData.AccessControl;
using Google.GData.Calendar;
using Google.GData.Client;
using Google.GData.Extensions;
using DataAccess;
using Common;
using Common.Views;


namespace BL_WServices
{
    /// <summary>
    /// This is the WCF Service which is implementing the interface IFaultsService
    /// </summary>
    public class FaultsService : IFaultsService
    {
        /// <summary>
        /// Returns the Fault Status of an Order
        /// </summary>
        /// <param name="orderID">Of type guid. Used to get the fault status of a particular product depending on the order</param>
        /// <param name="productID">Of type int. Used to get the fault status of a particular product</param>
        /// <returns>Returns string</returns>
        public string GetFaultsForOrder(Guid orderID, int productID)
        {
            return new FaultsRepository().GetFaultsForOrder(orderID, productID);
        }

        /// <summary>
        /// Returns a list of detailed filter transactions depending on the productID and date
        /// </summary>
        /// <param name="startDate">Of type Date. Used to get the order between the startDate</param>
        /// <param name="endDate">Of type Date. Used to get the order between the endDate</param>
        /// <param name="productID">Of type int. Used to get the productID</param>
        /// <param name="username">Of type string. Used to get the order depending on the username</param>
        /// <returns>Returns a list of detailed filter transactions depending on the productID, and the purchase dates</returns>
        public IQueryable<OrdersView> FilterTransactions(DateTime startDate, DateTime endDate, int productID, string username)
        {
            return new FaultsRepository().FilterTransactions(startDate, endDate, productID, username);
        }

        /// <summary>
        /// Gets a list of the fault categories
        /// </summary>
        /// <returns>Returns a list of the fault categories</returns>
        public IQueryable<FaultCategory> GetFaultCategories()
        {
            return new FaultsRepository().GetFaultCategories();
        }

        /// <summary>
        /// User adds fault to the database and also categorizes that fault.
        /// An email is sent to the user containing a generated PDF and barcode image.
        /// The PDF contains the Date the item was reported, the fault id, the faulty product id, and the fault details
        /// </summary>
        /// <param name="faultID">Of type guid. Used to create a new faultID</param>
        /// <param name="faultCatID">Of type int. Used to get the fault categoryID of the fault</param>
        /// <param name="orderID">Of type guid. Used to get the orderID</param>
        /// <param name="productID">Of type int. Used to get the productID</param>
        /// <param name="details">Of type string. Used so that the user enters the fault details of the product</param>
        /// <param name="barcode">Of type byte. Used to create the barcode</param>
        /// <param name="username">Of type username. Used to enter get the user's email address</param>
        public void AddFault(Guid faultID, int faultCatID, Guid orderID, int productID, string details, byte[] barcode, string username)
        {
            Fault f = new Fault();
            f.FaultID = faultID;
            f.FaultCategoryID = faultCatID;
            f.OrderID = orderID;
            f.ProductID = productID;

            FaultDetail fd = new FaultDetail();
            fd.FaultID = faultID;
            fd.Date = DateTime.Now;
            fd.Details = details;
            fd.StatusID = 1; //Fault Status: Reported

            FaultsRepository fr = new FaultsRepository();
            UsersRepository ur = new UsersRepository();

            string faultStatus = fr.GetFaultStatus(fd.StatusID);

            fr.Entity = ur.Entity;
            try
            {
                fr.Entity.Connection.Open();
                fr.Transaction = ur.Transaction = fr.Entity.Connection.BeginTransaction();

                fr.AddFault(f);
                fr.AddFaultDetails(fd);
                string email = ur.GetUserEmail(username);

                //Creating the Image from the generated barcode
                MemoryStream ms = new MemoryStream(); //Saving the PDF File to Memory - Used so it can be sent over e-mail. 
                ImageConverter ic = new ImageConverter();
                System.Drawing.Image imgBarcode = (System.Drawing.Image)ic.ConvertFrom(barcode);
                imgBarcode.Save(ms, ImageFormat.Jpeg);
                ms.Position = 0;
                ContentType ct = new ContentType();
                ct.MediaType = MediaTypeNames.Image.Jpeg;
                ct.Name = "Barcode - " + faultID.ToString();

                //Creating the PDF with details
                MemoryStream ms2 = new MemoryStream();
                Document doc = new Document();
                PdfWriter writer = PdfWriter.GetInstance(doc, ms2);
                doc.Open();

                PdfPTable table = new PdfPTable(5);
                PdfPCell header = new PdfPCell(new Phrase("Fault Details"));
                header.Colspan = 5;
                header.HorizontalAlignment = 1;
                header.Border = 0;
                table.AddCell(header);

                table.AddCell("Fault ID");
                table.AddCell("Product ID");
                table.AddCell("Date");
                table.AddCell("Fault Details");
                table.AddCell("Fault Status");

                table.AddCell(faultID.ToString());
                table.AddCell(productID.ToString());
                table.AddCell(DateTime.Now.ToShortDateString());
                table.AddCell(details);
                table.AddCell(faultStatus);

                doc.Add(table);

                writer.CloseStream = false;
                doc.Close();
                ms2.Position = 0;

                //Email is sent to the user with the PDF + Barcode
                MailMessage mm = new MailMessage();
                mm.To.Add(email);
                mm.From = new MailAddress("fabulousfashion00@gmail.com");
                mm.Subject = "Reported Fault Receipt";
                mm.Body = "This is your receipt for reporting your faulty product. We will contact you regarding an update regarding the faulty product shortly. Attached, you have the fault details together with the barcode.";
                mm.Body += "Yours sincerely, <br/> <b>Electros Ltd</b>";
                mm.Attachments.Add(new Attachment(ms, ct));
                mm.Attachments.Add(new Attachment(ms2, faultID + ".pdf"));

                mm.IsBodyHtml = true;

                SmtpClient client = new SmtpClient("smtp.gmail.com", 587);
                client.EnableSsl = true;
                client.DeliveryMethod = SmtpDeliveryMethod.Network;
                client.Credentials = new NetworkCredential("fabulousfashion00@gmail.com", "fabfashadmin");
                client.Send(mm);

                fr.Transaction.Commit();
            }
            catch (Exception ex)
            {
                fr.Transaction.Rollback();
            }
            finally
            {
                fr.Entity.Connection.Close();
            }
        }
        
        /// <summary>
        /// Gets a list of the faults
        /// </summary>
        /// <returns>Returns a list of the faults</returns>
        public IQueryable<Fault> GetAllFaults()
        {
            return new FaultsRepository().GetAllFaults();
        }

        /// <summary>
        /// Returns a list of fault details/log entries in descending order
        /// </summary>
        /// <returns>Returns a list of fault details/log entries in descending order, ordered by the date</returns>
        public IEnumerable<FaultView> SearchByDateDESC()
        {
            return new FaultsRepository().SearchByDateDESC();
        }

        /// <summary>
        /// Returns a list of faults depending on the startDate and endDate
        /// </summary>
        /// <param name="startDate">Of type DateTime. Used to get the earliest date</param>
        /// <param name="endDate">Of type DateTime. Used to get the latest date</param>
        /// <returns>Returns a list of faults depending on the startDate and endDate</returns>
        public IQueryable<FaultView> SearchByLogDate(DateTime startDate, DateTime endDate)
        {
            return new FaultsRepository().SearchByLogDate(startDate, endDate);
        }

        /// <summary>
        /// Returns a list of faults depending on the faultID
        /// </summary>
        /// <param name="faultID">Of type Guid. Used to get the faultID</param>
        /// <returns>Returns a list of faults depending on the faultID</returns>
        public IQueryable<FaultView> SearchByFaultID(Guid faultID)
        {
            return new FaultsRepository().SearchByFaultID(faultID);
        }

        /// <summary>
        /// Returns a list of faults depending on the username
        /// </summary>
        /// <param name="username">Of type string. Used to get the username</param>
        /// <returns>Returns a list of faults depending on the username</returns>
        public IQueryable<FaultView> SearchByClientID(string username)
        {
            return new FaultsRepository().SearchByClientID(username);
        }

        /// <summary>
        /// Returns the LogEntries by faultID, username, startDate and endDate
        /// </summary>
        /// <param name="faultID">Of type Guid. Used to get the faultID</param>
        /// <param name="username">Of type string. Used to get the username</param>
        /// <param name="startDate">Of type DateTime. Used to get the earliest date</param>
        /// <param name="endDate">Returns a list of faults depending on the startDate and endDate</param>
        /// <returns>Returns the LogEntries by faultID, username, startDate and endDate</returns>
        public IQueryable<FaultView> SearchByLogEntries(Guid faultID, string username, DateTime startDate, DateTime endDate)
        {
            return new FaultsRepository().SearchByLogEntries(faultID, username, startDate, endDate);
        }

        /// <summary>
        /// Get all the Log Entries for the Faults
        /// </summary>
        /// <returns>Returns all the log entries for the faults</returns>
        public IQueryable<FaultView> GetAllLogEntires()
        {
            return new FaultsRepository().GetAllLogEntires();
        }

        /// <summary>
        /// Gets a list of fault statuses
        /// </summary>
        /// <returns>Returns a list of fault statuses</returns>
        public IQueryable<FaultStatu> GetAllFaultStatuses()
        {
            return new FaultsRepository().GetAllFaultStatuses();
        }

        /// <summary>
        /// Used to add a new fault to the database and fault is categorized
        /// </summary>
        /// <param name="OrderID">Of type guid. Used to get the username depending on the orderID</param>
        /// <param name="faultID">Of type guid. Used to create a new faultID</param>
        /// <param name="details">Of type string. Used so that the user enters the fault details of the product</param>
        /// <param name="statusID">Of type int. Used to add the statusID</param>
        public void UpdateFault(Guid OrderID, Guid faultID, string details, int statusID)
        {
            FaultDetail fd = new FaultDetail();
            fd.FaultID = faultID;
            fd.Date = DateTime.Now;
            fd.Details = details;
            fd.StatusID = statusID;

            FaultsRepository fr = new FaultsRepository();
            UsersRepository ur = new UsersRepository();

            string faultStatus = fr.GetFaultStatus(fd.StatusID);

            fr.Entity = ur.Entity;
            try
            {
                fr.Entity.Connection.Open();
                fr.Transaction = ur.Transaction = fr.Entity.Connection.BeginTransaction();

                fr.AddFaultDetails(fd);
                string email = ur.GetUserEmailByOrder(OrderID);
                string mobileNo = ur.GetUserNumberByOrder(OrderID);

                /*//sms code
                // string with the URL - with user, password, api_id, mobile number of the user and the text to be sent
                 string apiURL = "http://api.clickatell.com/http/sendmsg?user=RebMint&password=baRdKRLgIdKcbc&api_id=3477201&to="+mobileNo+"&text=Your+Fault+Status+has+been+Updated";
                 Uri Address = new Uri(apiURL);

                 HttpWebRequest request = WebRequest.Create(Address) as HttpWebRequest;

                 request.Method = "GET";
                 request.ContentType = "text/xml";
                 using (HttpWebResponse response = request.GetResponse() as HttpWebResponse)
                 {
                     StreamReader reader = new StreamReader(response.GetResponseStream());
                     string strOutputXml = reader.ReadToEnd();
                 }*/

                
                //Google API Code
                //Create a new service
                CalendarService service = new CalendarService("ElectroSystem");
                service.setUserCredentials("fabulousfashion00@gmail.com", "fabfashadmin");
                
                //Create Google Calendar Event and send to user
                EventEntry entry = new EventEntry();
                entry.Title.Text = "Fault Status Updated";
                entry.Content.Content = "The fault status for your reported product has been updated. The fault is now: " + faultStatus;

                //Location of the Event
                Where eventLocation = new Where();
                eventLocation.ValueString = "Electros Ltd";
                entry.Locations.Add(eventLocation);

                //Time of the Event
                When eventTime = new When(DateTime.Now, DateTime.Now.AddHours(2));
                entry.Times.Add(eventTime);

                Who guest = new Who();
                guest.Email = email;
                guest.Rel = "EVENT_ATTENDEE";
                entry.Participants.Add(guest);
                
                Uri postUri = new Uri("https://www.google.com/calendar/feeds/default/private/full");
                
                AtomEntry insertedEntry = service.Insert(postUri, entry);
                


                //Email is sent to the user to inform him/her that the fault status has been updated
                MailMessage mm = new MailMessage();
                mm.To.Add(email);
                mm.From = new MailAddress("fabulousfashion00@gmail.com");
                mm.Subject = "Fault has been updated!";
                mm.Body = "Dear User, <br/> The fault status for your reported product has been updated. It's fault is now: " + faultStatus + ". <br/>";
                mm.Body += "Yours sincerely, <br/> <b>Electros Ltd</b>";

                mm.IsBodyHtml = true;

                SmtpClient client = new SmtpClient("smtp.gmail.com", 587);
                client.EnableSsl = true;
                client.DeliveryMethod = SmtpDeliveryMethod.Network;
                client.Credentials = new NetworkCredential("fabulousfashion00@gmail.com", "fabfashadmin");
                client.Send(mm);

                fr.Transaction.Commit();
                
            }
            catch (Exception ex)
            {
                fr.Transaction.Rollback();
            }
            finally
            {
                fr.Entity.Connection.Close();
            }
        }
    }
}
